package br.com.spam.pipeline.iu;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import br.com.spam.pipeline.core.PipelineSimulator;
import br.com.spam.pipeline.phase.Phase;

public class IU_Datashow extends JFrame implements Observer
{
	private final Collection<Observer> observers = new LinkedList<Observer>();
	private static final long serialVersionUID = -4724786829589998903L;

	private PipelineSimulator currentPipeline;

	private JPanel principal = new JPanel();
	private JPanel phases = new JPanel();
	private IU_ExOptions execution;
	private IU_RegisterBank registerBank;
	private IU_Processor processor;
	private IU_Memory memory;

	public IU_Datashow()
	{
		super("Pipeline Simulator");

		this.onPipelineChanged(new Observer()
		{
			@Override
			public void update(Observable o, Object arg)
			{
				IU_Datashow.this.setUpPhases();
				IU_Datashow.this.update();
			}
		});

		this.setResizable(false);
		this.setSize(1024, 768);

		this.execution = new IU_ExOptions(this);
		this.registerBank = new IU_RegisterBank(this);
		this.processor = new IU_Processor(this);
		this.memory = new IU_Memory(this);

		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.getContentPane().add(this.principal);
		this.principal.setLayout(new BorderLayout());
		this.principal.setBackground(Color.WHITE);

		// CENTER
		this.putImage();

		// NORTH
		JPanel aux1 = new JPanel();
		aux1.setLayout(new BorderLayout());
		this.principal.add(aux1, BorderLayout.NORTH);
		aux1.add(this.phases, BorderLayout.CENTER);
		aux1.add(this.execution, BorderLayout.EAST);

		// EAST
		JPanel aux2 = new JPanel();
		aux2.setLayout(new BorderLayout());
		this.principal.add(aux2, BorderLayout.EAST);
		aux2.add(this.memory, BorderLayout.NORTH);
		aux2.add(this.processor, BorderLayout.CENTER);
		aux2.add(this.registerBank, BorderLayout.SOUTH);
	}

	public void play()
	{
		this.pipeline().play();
	}

	public void next()
	{
		this.pipeline().next();
	}

	public void pause()
	{
		this.pipeline().pause();
	}

	public PipelineSimulator pipeline()
	{
		return this.currentPipeline;
	}

	public void onPipelineChanged(Observer observer)
	{
		this.observers.add(observer);
	}

	public void load(String sourceCode)
	{
		System.out.println("load " + sourceCode);
		if (this.currentPipeline != null)
		{
			this.currentPipeline.deleteObservers();
		}

		this.currentPipeline = new PipelineSimulator(sourceCode);
		this.currentPipeline.addObserver(this);

		for (Observer observer : this.observers)
		{
			observer.update(null, this.pipeline());
		}
	}

	private void putImage()
	{
		JLabel image = new JLabel(new ImageIcon("resources/pipeline.png"));
		this.principal.add(image, BorderLayout.CENTER);
	}

	private void setUpPhases()
	{
		this.phases.removeAll();
		this.phases.setLayout(new GridLayout(0, 5));

		for (Phase p : this.pipeline().getPhases())
		{
			this.phases.add(new IU_PipelinePhase(p));
		}

		this.phases.updateUI();
	}

	@Override
	public void update(Observable o, Object arg)
	{
		this.update();
	}

	private void update()
	{
		for (int i = 0; i < this.phases.getComponents().length; i++)
			((IU_PipelinePhase) this.phases.getComponent(i)).update();

		this.registerBank.update();
		this.processor.update();
		this.memory.update();
	}
}
